﻿using Abp.BackgroundJobs;
using Abp.Domain.Services;
using Abp.Events.Bus;
using Abp.ObjectMapping;
using Abp.Runtime.Caching;
using Abp.Runtime.Validation;
using Abp.Timing;
using Abp.UI;
using AVIS.OutBound.AWD;
using AVIS.OutBound.CarGroups;
using AVIS.OutBound.Orders.Cache;
using AVIS.OutBound.RateCodes;
using AVIS.OutBound.Stores;
using AVIS.OutBound.ThirdOrders;
using AVIS.OutBound.Wizard;
using AVIS.OutBound.WizardAgent;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AVIS.OutBound.Orders
{
    /// <summary>
    /// 订单的领域服务
    /// </summary>
    public class OrderManager : DomainService, IOrderManager
    {
        #region 构造函数
        public IEventBus EventBus { get; set; }

        private readonly ICacheManager _cacheManager;
        private readonly IObjectMapper _objectMapper;
        private readonly IStoreManager _storeManager;
        private readonly IAWDManager _awdManager;
        private readonly IRateCodeManager _rateCodeMananger;
        private readonly ICarGroupManager _carGroupManager;
        private readonly IAAOrderManager _aaOrderManager;
        private readonly IYouYouOrderManager _youyouOrderManager;
        private readonly WizardVehRetResAgent _wizardRetAgent;
        private readonly IOrderRepository _OrderRepository;
        private readonly IBackgroundJobManager _backgroundJobManager;
        private readonly IWizardManager _wizardManager;
        public OrderManager(ICacheManager cacheManager,
                IAWDManager awdManager,
                IObjectMapper objectMapper,
                IStoreManager storeManager,
                IAAOrderManager aaOrderManager,
                IYouYouOrderManager youyouOrderManager,
                IRateCodeManager RateCodeMananger,
                ICarGroupManager carGroupManager,
                IBackgroundJobManager backgroundJobManager,
                IOrderRepository OrderRepository,
                IWizardManager wizardManager)
        {
            _cacheManager = cacheManager;
            _awdManager = awdManager;
            _objectMapper = objectMapper;
            _storeManager = storeManager;
            _aaOrderManager = aaOrderManager;
            _youyouOrderManager = youyouOrderManager;
            _rateCodeMananger = RateCodeMananger;
            _carGroupManager = carGroupManager;
            _wizardRetAgent = new WizardVehRetResAgent();
            _OrderRepository = OrderRepository;
            _backgroundJobManager = backgroundJobManager;
            _wizardManager = wizardManager;

            EventBus = NullEventBus.Instance;
        }
        #endregion

        /// <summary>
        /// 提交订单到Wizard接口并保持订单信息到数据库
        /// </summary>
        /// <param name="order">订单</param>
        /// <returns></returns>
        public Order SubmitOrder(Order order)
        {
            var isNewOrder = string.IsNullOrEmpty(order.OrderNo);

            // 1. 判断是否可以修改
            if (CanModifyOrder(order) == false)
            {
                throw new UserFriendlyException("该订单不支持修改，如需修改，请取消后重新预订。");
            }

            // 2. 校验订单信息
            CheckVaild(order);

            // 3. 通过Wizard接口提交订单信息
            var rs = _objectMapper.Map<SubmitOrderRequest>(order);
            rs.AWD = _awdManager.GetRealAWDCode(rs.AWD); // 获取真实的AWD号，一般国内的AWD号是以CN开头的
            var response = _wizardRetAgent.SubmitOrder(rs);
            _wizardManager.HandleErrorMessage(response); // 处理Wizard结果的错误信息

            // 4. 保存订单信息到数据库
            order.OrderNo = response.Data.OrderNo;
            order.CurrencyCode = response.Data.CurrencyCode;
            order.Amount = response.Data.QuotedTMI;
            order.AWD = _awdManager.GetRealAWDCode(order.AWD);    ///获取真实的AWD
            _OrderRepository.SaveOrder(order);

            // 5. 触发订单已提交事件.
            EventBus.Trigger(new OrderSubmittedEventData { Order = order, IsNewOrder = isNewOrder });

            // 记录日志
            Logger.InfoFormat("订单信息（{0},{1}）提交成功。<BR />{2}",
                order.OrderNo, order.Surname, Newtonsoft.Json.JsonConvert.SerializeObject(order));

            return order;
        }

        /// <summary>
        /// 取消订单，通过Wizard接口取消并修改数据库的订单信息，最后触发订单取消事件
        /// </summary>
        /// <param name="request">取消订单请求参数</param>
        /// <returns></returns>
        public bool CancelOrder(AgentCancelOrderRequest request)
        {
            // 1. 通过Wizard接口取消订单
            var rs = _objectMapper.Map<CancelOrderRequest>(request);
            var response = _wizardRetAgent.CancelOrder(rs);
            _wizardManager.HandleErrorMessage(response); // 处理Wizard结果的错误信息

            // 2. 更新取消状态和取消原因到数据库
            var dbOrder = GetOrderInDBOrCache(request.OrderNo, request.Surname);
            if (dbOrder != null)
            {
                dbOrder.IsCancel = true;
                dbOrder.CancelReason = request.CancelReason;
                _OrderRepository.CancelOrder(dbOrder);
            }

            // 3. 触发订单已取消事件.
            EventBus.Trigger(new OrderCanceledEventData { Order = dbOrder });

            return true;
        }

        /// <summary>
        /// 查询订单
        /// </summary>
        /// <param name="OrderNo"></param>
        /// <param name="Surname"></param>
        /// <returns></returns>
        public Order QueryOrder(string orderNo, string surname)
        {
            // 1. 从获取Wizard获取订单数据
            var request = new OrderQueryRequest { ReservationNumber = orderNo, Surname = surname };
            var response = _wizardRetAgent.OrderQuery(request);
            _wizardManager.HandleErrorMessage(response); // 处理Wizard结果的错误信息

            // 2. 获取数据库中的订单数据
            var dbOrder = GetOrderInDBOrCache(orderNo, surname);

            // 3. 判断是否已经支付
            if (response.Data.IsPaid)
            {
                throw new UserFriendlyException("您的订单已付款，如需修改请联系操作人员。");
            }

            // 4. 合并Wizard接口的订单和数据库的订单信息
            var order = MergeOrderInfo(response.Data, dbOrder);

            // 5. 处理订单中的取还车门店信息
            order.PickUpStore = _storeManager.GetStoreByCode(order.PickUpStoreCode);
            order.ReturnStore = _storeManager.GetStoreByCode(order.ReturnStoreCode);

            // 6. 处理套餐内容
            order.RatePackage = _rateCodeMananger.GetRateCode(order);

            return order;
        }

        /// <summary>
        /// 获取订单信息（本地数据库）
        /// </summary>
        /// <param name="orderNo">订单号</param>
        /// <returns></returns>
        public Order GetDBOrder(string orderNo)
        {
            return GetOrderInDBOrCache(orderNo, "");
        }
        #region 私有方法

        /// <summary>
        /// 获取订单信息
        /// </summary>
        /// <param name="orderNo">订单号</param>
        /// <param name="surname">用户的姓</param>
        /// <returns></returns>
        private Order GetOrderInDBOrCache(string orderNo, string surname)
        {
            var cacheItem = _cacheManager.GetOrderCache().Get(orderNo, f =>
            {
                return _objectMapper.Map<OrderCacheItem>(_OrderRepository.GetOrder(orderNo, surname));
            });
            return _objectMapper.Map<Order>(cacheItem);
        }

        /// <summary>
        /// 合并Wizard接口的订单和数据库的订单信息
        /// </summary>
        /// <param name="response"></param>
        /// <param name="order"></param>
        /// <returns></returns>
        private Order MergeOrderInfo(OrderQueryDto dto, Order dbOrder)
        {
            var order = dbOrder ?? new Order // DB中没有订单信息，可能是从其他途径下的订单
            {
                OrderId = Guid.NewGuid().ToString(),
                BookingDate = Abp.Timing.Clock.Now,
                OrderStep = 6,
                IATA = "",
                IATAType = 5,
                PayType = "2",
            };

            if (!string.IsNullOrWhiteSpace(dto.Firstname) && dto.Firstname != order.Firstname)
            {
                order.Firstname = dto.Firstname;
            }
            if (!string.IsNullOrWhiteSpace(dto.Surname) && dto.Surname != order.Surname)
            {
                order.Surname = dto.Surname;
            }

            if (!string.IsNullOrWhiteSpace(dto.CurrencyCode) && dto.CurrencyCode != order.CurrencyCode)
            {
                order.CurrencyCode = dto.CurrencyCode;
            }

            if (!string.IsNullOrWhiteSpace(dto.OrderNo) && dto.OrderNo != order.OrderNo)
            {
                order.OrderNo = dto.OrderNo;
            }

            if (dto.PickupDateTime.Ticks > 0 && dto.PickupDateTime != order.PickupDateTime)
            {
                order.PickupDateTime = dto.PickupDateTime;
            }

            if (dto.ReturnDateTime.Ticks > 0 && dto.ReturnDateTime != order.ReturnDateTime)
            {
                order.ReturnDateTime = dto.ReturnDateTime;
            }

            if (!string.IsNullOrWhiteSpace(dto.PickUpStoreCode) && dto.PickUpStoreCode != order.PickUpStoreCode)
            {
                order.PickUpStoreCode = dto.PickUpStoreCode;
            }

            if (!string.IsNullOrWhiteSpace(dto.ReturnStoreCode) && dto.ReturnStoreCode != order.ReturnStoreCode)
            {
                order.ReturnStoreCode = dto.ReturnStoreCode;
            }

            if (dto.QuotedTMI > 0 && dto.QuotedTMI != order.Amount)
            {
                order.Amount = dto.QuotedTMI;
            }

            if (!string.IsNullOrWhiteSpace(dto.RateCode) && dto.RateCode != order.RateCode)
            {
                order.RateCode = dto.RateCode;
            }

            if (!string.IsNullOrWhiteSpace(dto.SIPPCode) && dto.SIPPCode != order.SIPPCode)
            {
                order.SIPPCode = dto.SIPPCode;
            }

            order.RentalLength = int.Parse(dto.CarGroup.RentalLength);

            var rentalUnit = dto.CarGroup.RentalUnit.ToLower() == "day" ? "天" : dto.CarGroup.RentalUnit;
            if (!string.IsNullOrWhiteSpace(rentalUnit) && rentalUnit != order.RentalUnit)
            {
                order.RentalUnit = rentalUnit;
            }

            if (dto.CouponDiscountAmount > 0 && dto.CouponDiscountAmount != order.CouponDiscountAmount)
            {
                order.CouponDiscountAmount = dto.CouponDiscountAmount;
            }
            if (!string.IsNullOrWhiteSpace(dto.CouponDiscountCurrencyCode) && dto.CouponDiscountCurrencyCode != order.CouponDiscountCurrencyCode)
            {
                order.CouponDiscountCurrencyCode = dto.CouponDiscountCurrencyCode;
            }

            var awd = string.IsNullOrWhiteSpace(dto.AWD) ? order.AWD : dto.AWD;
            order.AWD = _awdManager.GetCNAWDCode(awd);

            // 合并车组信息
            order.CarGroup = ConvertDtoToCarGroup(dto.CarGroup, order.CarGroup, _storeManager.GetStoreByCode(dto.PickUpStoreCode));

            return order;
        }

        /// <summary>
        /// 合并Wizard查询订单接口的车组信息和数据库的车组信息
        /// </summary>
        /// <returns></returns>
        private CarGroup ConvertDtoToCarGroup(CarGroupDto dto, CarGroup dbCarGroup, Store pickupStore)
        {
            var carGroup = dbCarGroup ?? new CarGroup();
            var dtoCarGroup = _carGroupManager.BuildCarGroup(dto, pickupStore);

            if (!string.IsNullOrWhiteSpace(dtoCarGroup.ModelName) && dtoCarGroup.ModelName != carGroup.ModelName)
            {
                carGroup.ModelName = dtoCarGroup.ModelName;
            }

            var modelCode = dtoCarGroup.ModelName.Substring(6, 2).Trim();
            if (!string.IsNullOrWhiteSpace(modelCode) && modelCode != carGroup.ModelCode)
            {
                carGroup.ModelCode = modelCode;
            }

            if (!string.IsNullOrWhiteSpace(dtoCarGroup.SIPPCode) && dtoCarGroup.SIPPCode != carGroup.SIPPCode)
            {
                carGroup.SIPPCode = dtoCarGroup.SIPPCode;
            }

            if (dtoCarGroup.Price > 0 && dtoCarGroup.Price != carGroup.Price)
            {
                carGroup.Price = dtoCarGroup.Price;
            }

            if (!string.IsNullOrWhiteSpace(dtoCarGroup.CurrencyCode) && dtoCarGroup.CurrencyCode != carGroup.CurrencyCode)
            {
                carGroup.CurrencyCode = dtoCarGroup.CurrencyCode;
            }

            if (!string.IsNullOrWhiteSpace(dtoCarGroup.PictureURL) &&
                (string.IsNullOrWhiteSpace(carGroup.PictureURL) || !carGroup.PictureURL.Contains(dtoCarGroup.PictureURL)))
            {
                carGroup.PictureURL = dtoCarGroup.PictureURL;
            }

            if (!string.IsNullOrWhiteSpace(dtoCarGroup.RateCode) && dtoCarGroup.RateCode != carGroup.RateCode)
            {
                carGroup.RateCode = dtoCarGroup.RateCode;
            }

            if (dtoCarGroup.Feature != null)
            {
                if (!string.IsNullOrWhiteSpace(dtoCarGroup.Feature.Category))
                {
                    carGroup.Feature.Category = dtoCarGroup.Feature.Category;
                }

                if (!string.IsNullOrWhiteSpace(dtoCarGroup.Feature.Doors))
                {
                    carGroup.Feature.Doors = dtoCarGroup.Feature.Doors;
                }

                if (dtoCarGroup.Feature.HasAirConditioning.HasValue)
                {
                    carGroup.Feature.HasAirConditioning = dtoCarGroup.Feature.HasAirConditioning.Value;
                }

                if (dtoCarGroup.Feature.IsAutomatic.HasValue)
                {
                    carGroup.Feature.IsAutomatic = dtoCarGroup.Feature.IsAutomatic.Value;
                }

                if (!string.IsNullOrWhiteSpace(dtoCarGroup.Feature.Seats))
                {
                    carGroup.Feature.Seats = dtoCarGroup.Feature.Seats;
                }

                if (!string.IsNullOrWhiteSpace(dtoCarGroup.Feature.Suitcases))
                {
                    carGroup.Feature.Suitcases = dtoCarGroup.Feature.Suitcases;
                }

                if (!string.IsNullOrWhiteSpace(dtoCarGroup.Feature.FeaturesString))
                {
                    carGroup.Feature.FeaturesString = dtoCarGroup.Feature.FeaturesString;
                }
            }

            if (dtoCarGroup.PriceInclue.Coverages.Count > 0
                && dtoCarGroup.PriceInclue.Coverages.Count != carGroup.PriceInclue.Coverages.Count)
            {
                carGroup.PriceInclue.Coverages = dtoCarGroup.PriceInclue.Coverages.Select(c =>
                    new PriceIncludeCoverage
                    {
                        Code = c.Code,
                        Content = c.Content,
                        InsuranceExcessAmount = c.InsuranceExcessAmount,
                        InsuranceExcessCurrencyCode = c.InsuranceExcessCurrencyCode,
                    }).ToList();
            }

            if (dtoCarGroup.PriceInclue.VehicleCharges.Count > 0
                && dtoCarGroup.PriceInclue.VehicleCharges.Count != carGroup.PriceInclue.VehicleCharges.Count)
            {
                carGroup.PriceInclue.VehicleCharges = dtoCarGroup.PriceInclue.VehicleCharges;
            }

            var distance = dtoCarGroup.PriceInclue.Distance;
            if (distance != null)
            {
                carGroup.PriceInclue.Distance = new PriceIncludeDistance
                {
                    DistanceUnit = distance.DistanceUnit,
                    PeriodUnit = distance.PeriodUnit,
                    Quantity = distance.Quantity,
                    Unlimited = distance.Unlimited,
                };
            }

            if (dtoCarGroup.PriceInclue.Contents.Count > 0
                && dtoCarGroup.PriceInclue.Contents.Count != carGroup.PriceInclue.Contents.Count)
            {
                carGroup.PriceInclue.Contents = dtoCarGroup.PriceInclue.Contents;
            }

            // 合并增值服务
            foreach (var equip in dtoCarGroup.CarEquipments)
            {
                var oldEquip = carGroup.CarEquipments.FirstOrDefault(e => e.Type == equip.Type);
                if (oldEquip == null)
                {
                    // 增加增值服务（可能订单表是空的）
                    carGroup.CarEquipments.Add(_objectMapper.Map<CarEquipment>(equip));
                }
                else
                {
                    if (!string.IsNullOrEmpty(equip.Type) && oldEquip.Type != equip.Type)
                    {
                        oldEquip.Type = equip.Type;
                    }

                    if (!string.IsNullOrEmpty(equip.Amount) && oldEquip.Amount != equip.Amount)
                    {
                        oldEquip.Amount = equip.Amount;
                    }

                    if (equip.Quantity > 0 && oldEquip.Quantity != equip.Quantity)
                    {
                        oldEquip.Quantity = equip.Quantity;
                    }

                    if (!string.IsNullOrEmpty(equip.CurrencyCode) && oldEquip.CurrencyCode != equip.CurrencyCode)
                    {
                        oldEquip.CurrencyCode = equip.CurrencyCode;
                    }

                    if (!string.IsNullOrEmpty(equip.UnitName) && oldEquip.UnitName != equip.UnitName)
                    {
                        oldEquip.UnitName = equip.UnitName;
                    }
                    if (!string.IsNullOrEmpty(equip.UnitPrice) && oldEquip.UnitPrice != equip.UnitPrice)
                    {
                        oldEquip.UnitPrice = equip.UnitPrice;
                    }
                }
            }
            carGroup.CarEquipments = carGroup.CarEquipments.Where(e => e.Quantity > 0).ToList(); // 排除购买数量为零的增值服务

            return carGroup;
        }

        /// <summary>
        /// 检验订单是否可以被修改
        /// </summary>
        /// <param name="order">订单信息</param>
        /// <returns></returns>
        private bool CanModifyOrder(Order order)
        {
            // 如果存在游友订单，则不可以修改
            if (_youyouOrderManager.IsExist(order.YouyouOrderID))
            {
                Logger.Info($"订单（{order.OrderNo}）存在境外移动wifi订单，故订单不可以修改");
                throw new UserFriendlyException("您已创建境外移动WiFi订单，Avis订单不支持修改，如需修改，请取消后重新预订。");
                return false;
            }

            // 如果存在AA接机订单，则不可以修改
            if (_aaOrderManager.IsExist(order.OrderNo))
            {
                Logger.Info($"订单（{order.OrderNo}）存在AA接机订单，故订单不可以修改");
                throw new UserFriendlyException("您已预定接机服务，Avis订单不支持修改，如需修改，请取消后重新预订。");
                return false;
            }

            return true;
        }

        /// <summary>
        /// 校验订单信息是否有效
        /// </summary>
        /// <param name="order"></param>
        /// <returns></returns>
        private bool CheckVaild(Order order)
        {
            // 判断常旅客卡号是否正确
            var awdNumber = _awdManager.GetAWDNumberCache(order.AWD);
            if (awdNumber != null && !string.IsNullOrWhiteSpace(awdNumber.FTP))
            {
                if (awdNumber.FTP != order.FTNProgramme)
                {
                    throw new UserFriendlyException(awdNumber.FTPRemark);
                }
            }

            // TODO 校验用户姓和名必须为拼音

            // 校验预订单对象
            if (order.PickupDateTime <= Clock.Now)
            {
                throw new UserFriendlyException("无效的取车时间");
            }

            if (order.ReturnDateTime <= Clock.Now)
            {
                throw new UserFriendlyException("无效的还车时间");
            }

            if (order.RentalLength <= 0)
            {
                throw new UserFriendlyException("租期无效，请重新选择取车时间和还车时间");
            }

            if (string.IsNullOrWhiteSpace(order.PickUpStoreCode))
            {
                throw new UserFriendlyException("取车门店不能为空");
            }

            if (string.IsNullOrWhiteSpace(order.ReturnStoreCode))
            {
                throw new UserFriendlyException("还车门店不能为空");
            }

            if (string.IsNullOrWhiteSpace(order.SIPPCode))
            {
                throw new UserFriendlyException("请先选择车组套餐！");
            }

            if (string.IsNullOrWhiteSpace(order.RateCode))
            {
                throw new UserFriendlyException("请先选择车组套餐！");
            }

            if (string.IsNullOrWhiteSpace(order.Surname))
            {
                throw new UserFriendlyException("用户姓名不能为空！");
            }

            if (string.IsNullOrWhiteSpace(order.Firstname))
            {
                throw new UserFriendlyException("用户姓名不能为空！");
            }

            if (string.IsNullOrWhiteSpace(order.Email))
            {
                throw new UserFriendlyException("邮箱不能为空！");
            }

            if (string.IsNullOrWhiteSpace(order.Telephone))
            {
                throw new UserFriendlyException("电话号码不能为空！");
            }

            return true;
        }

        #endregion
    }
}
